package com.kjlink.internal.report4vue.statictics.service;

import com.kjlink.internal.report4vue.base.service.BaseApiService;
import com.kjlink.internal.report4vue.plan.model.Plan;
import com.kjlink.internal.report4vue.statictics.mapper.ApiStatMapper;
import com.kjlink.internal.report4vue.statictics.model.ApiUserJiraVo;
import com.kjlink.internal.workreport.helper.ReportCommonHelper;
import com.kjlink.internal.workreport.report.model.WorkReport;
import com.kjlink.internal.workreport.stats.lookup.UserWeekLookup;
import com.kjlink.internal.workreport.stats.vo.EchartsHeatmapVo;
import com.kjlink.internal.workreport.user.model.User;
import com.kjlink.internal.workreport.user.service.UserService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 描述:
 * 人员计划统计  service
 *
 * @author Vic.xu
 * @since 2025-03-06 10:40
 */
@Service
public class ApiStatPlanService extends BaseApiService {

    @Resource
    private ApiStatMapper apiStatMapper;

    @Resource
    private UserService userService;

    /**
     * 人员计划统计: 热力图
     */
    public EchartsHeatmapVo statPlan(UserWeekLookup lookup) {
        EchartsHeatmapVo heatmap = new EchartsHeatmapVo();
        //y 轴 日期
        List<LocalDate> dateRange = ReportCommonHelper.getDateRange(lookup.getStartDate(), lookup.getEndDate());
        // 日志转为 MM-dd
        List<String> yAxios = dateRange.stream().map(date -> date.format(ReportCommonHelper.MONTH_DAY_FORMAT_FORMATTER)).collect(Collectors.toList());
        heatmap.setyAxisData(yAxios);
        List<User> userByGroupIds = userService.findUserByGroupIds(lookup.getGroupIds());
        // x 轴 用户名
        List<String> xAxios = userByGroupIds.stream().map(User::getUserName).collect(Collectors.toList());
        heatmap.setxAxisData(xAxios);
        if (CollectionUtils.isEmpty(xAxios)) {
            return heatmap;
        }
        // 用户的jira 计划列表
        List<ApiUserJiraVo> userJiraPlanList = apiStatMapper.findUserJiraPlanList(lookup);
        // userJiraPlanList转 map  key为用户id，value 为 ApiUserJiraVo list
        Map<Integer, List<ApiUserJiraVo>> userJiraPlanMap = userJiraPlanList.stream().collect(Collectors.groupingBy(ApiUserJiraVo::getUserId));

        List<List<Number>> heatmapData = new ArrayList<>();

        Map<String, Object> dataDetails = new HashMap<>();

        //构建每个坐标的信息 x轴 是用户  y轴是日期
        for (int x = 0; x < xAxios.size(); x++) {
            for (int y = 0; y < yAxios.size(); y++) {
                LocalDate date = dateRange.get(y);
                String key = x + "_" + y;
                Integer userId = userByGroupIds.get(x).getId();
                Pair<Integer, String> pair = buildAxiosDetail(date, userId, userJiraPlanMap);
                // 每个数据格式为[xIndex, yIndex, value]
                heatmapData.add(Stream.of(x, y, pair.getLeft()).collect(Collectors.toList()));
                //  每个坐标的详细数据：key： xIndex + "_" + yIndex， value = (jira 号 + jira content) list
                dataDetails.put(key, pair.getRight());
            }
        }
        heatmap.setHeatmapData(heatmapData);
        heatmap.setDataDetails(dataDetails);
        return heatmap;
    }

    /**
     * 构建每个坐标的详细：计划数量和计划详情
     *
     * @return 构建后的数据 left： 数量， right：计划详情
     */
    public Pair<Integer, String> buildAxiosDetail(LocalDate date, Integer userId, Map<Integer, List<ApiUserJiraVo>> userJiraPlanMap) {
        //当前用户的全部计划列表
        List<ApiUserJiraVo> plans = userJiraPlanMap.get(userId);
        if (CollectionUtils.isEmpty(plans)) {
            return Pair.of(0, "");
        }
        // 使用for 循环 过滤出plans  属于当前日期的计划：  planStartDate <=  date <= planEndDate
        int count = 0;
        StringBuilder detail = new StringBuilder();
        for (ApiUserJiraVo plan : plans) {
            if (!plan.getPlanStartDate().isAfter(date) && !plan.getPlanEndDate().isBefore(date)) {
                count++;
                detail.append(plan.getJiraCode()).append(":").append(StringUtils.abbreviate(plan.getJiraContent(), 30)).append("<br/>");
            }
        }
        return Pair.of(count, detail.toString());
    }


    /**
     * 查询出用户的指定时间内jira计划
     */
    public List<ApiUserJiraVo> findUserJiraPlanList(UserWeekLookup lookup) {
        return apiStatMapper.findUserJiraPlanList(lookup);
    }


    /**
     * 开发计划统计： 热力图 (计划不再设置于jira中，而是直接放在计划表中)
     * 1. 查询出用户在指定时间段内，计划表中的jira计划
     * 2. 如果开始时间小于当前时间，则从开始时间到当前时间内查询出日报，作为已经完成的内容
     * 3. 如果结束时间大于当前时间，则从当前时间到结束时间查询出计划，做为未来需完成的内容
     * 4. x轴：时间  y轴：用户名
     * 5. 热力图的数据调整为 当天完成的工时或者计划的工时
     */
    public EchartsHeatmapVo planHeatmap(UserWeekLookup lookup) {
        EchartsHeatmapVo heatmap = new EchartsHeatmapVo();
        //x 轴 日期
        List<LocalDate> dateRange = ReportCommonHelper.getDateRange(lookup.getStartDate(), lookup.getEndDate());
        // 日期转为 MM-dd
        List<String> xAxios = dateRange.stream().map(date -> date.format(ReportCommonHelper.MONTH_DAY_FORMAT_FORMATTER)).collect(Collectors.toList());
        heatmap.setxAxisData(xAxios);
        // y 轴 用户名
        List<User> userByGroupIds = userService.findUserByGroupIds(lookup.getGroupIds());
        if (CollectionUtils.isEmpty(userByGroupIds)) {
            return heatmap;
        }
        //查询出指定时间内[开始时间 —— 今天之前]的日报
        List<WorkReport> workReportList = getWorkReportList(lookup);
        Map<Integer, List<WorkReport>> workReportMap = workReportList.stream().collect(Collectors.groupingBy(WorkReport::getUserId));
        // 根据条件计划列表
        List<Plan> planList = apiStatMapper.findPlanList(lookup);


        Map<Integer, List<Plan>> planMap = planList.stream().collect(Collectors.groupingBy(Plan::getUserId));

        // 过滤用户：当whole为false时，只保留有数据的用户
        userByGroupIds = filterUsersByData(userByGroupIds, dateRange, workReportMap, planMap, lookup.getWhole());
        // 构建y轴（基于过滤后的用户）

        List<String> yAxios = userByGroupIds.stream().map(User::getUserName).collect(Collectors.toList());
        heatmap.setyAxisData(yAxios);

        if (CollectionUtils.isEmpty(yAxios)) {
            return heatmap;
        }

        List<List<Number>> heatmapData = new ArrayList<>();

        Map<String, Object> dataDetails = new HashMap<>();

        //构建每个坐标的信息 x轴 是日期  y轴是用户名
        for (int x = 0; x < xAxios.size(); x++) {
            for (int y = 0; y < yAxios.size(); y++) {
                String key = x + "_" + y;
                // 某日 某个用户的工时 或者计划工时
                LocalDate date = dateRange.get(x);
                Integer userId = userByGroupIds.get(y).getId();
                // 今天之前的 则基于日报构建，今天之后的 则基于计划构建
                Pair<Number, String> pair = date.isBefore(LocalDate.now()) ? buildAxiosDetailByReport(date, userId, workReportMap) : buildAxiosDetailByPlan(date, userId, planMap);
                // 每个数据格式为[xIndex, yIndex, value]; value=工时
                heatmapData.add(Stream.of(x, y, pair.getLeft()).collect(Collectors.toList()));
                //  每个坐标的详细数据：key： xIndex + "_" + yIndex， value = (jira 号 + jira content) list
                dataDetails.put(key, pair.getRight());
            }
        }
        heatmap.setHeatmapData(heatmapData);
        heatmap.setDataDetails(dataDetails);
        return heatmap;
    }

    /**
     * 根据日报构建每个坐标的详细：日报工时和日报详情
     */
    public Pair<Number, String> buildAxiosDetailByReport(LocalDate date, Integer userId, Map<Integer, List<WorkReport>> workReportMap) {
        List<WorkReport> workReports = workReportMap.get(userId);
        if (CollectionUtils.isEmpty(workReports)) {
            return Pair.of(0, "");
        }
        BigDecimal hour = BigDecimal.ZERO;
        StringBuilder detail = new StringBuilder();
        detail.append("<strong >日报:</strong><br/>");
        for (WorkReport workReport : workReports) {
            if (date.equals(workReport.getDate())) {
                hour = hour.add(workReport.getDurationHour());
                detail.append(workReport.getJira()).append(" [" + workReport.getDurationHour() + "] ").append(":").append(StringUtils.abbreviate(workReport.getContent(), 30)).append("<br/>");
            }
        }
        return Pair.of(hour, detail.toString());
    }

    /**
     * 根据计划 构建每个坐标的详细：计划工时和计划详情
     */
    public Pair<Number, String> buildAxiosDetailByPlan(LocalDate date, Integer userId, Map<Integer, List<Plan>> planMap) {
        List<Plan> planList = planMap.get(userId);
        if (CollectionUtils.isEmpty(planList)) {
            return Pair.of(0, "");
        }
        BigDecimal hour = BigDecimal.ZERO;
        StringBuilder detail = new StringBuilder();
        detail.append("<strong  style=\"color:red;\">计划:</strong><br/>");
        for (Plan plan : planList) {
            if (date.equals(plan.getDate())) {
                hour = hour.add(plan.getDuration());
                detail.append(plan.getJira()).append(" [" + plan.getDuration() + "] ").append(":").append(StringUtils.abbreviate(plan.getNote(), 30)).append("<br/>");
            }
        }
        return Pair.of(hour, detail.toString());
    }

    /**
     * 查询出指定时间内[开始时间 —— 今天之前]的日报
     */
    private List<WorkReport> getWorkReportList(UserWeekLookup lookup) {
        List<WorkReport> workReportList = new ArrayList<>();
        // 开始时间 不在今天之前 则不查询日报
        if (!lookup.getStartDate().isBefore(LocalDate.now())) {
            return workReportList;
        }

        List<WorkReport> list = apiStatMapper.findCompletionReportList(lookup);
        return list;

    }

    /**
     * 过滤用户：当whole为false时，只保留有数据的用户
     *
     * @param allUsers      所有用户
     * @param dateRange     日期范围
     * @param workReportMap 用户id -> 日报列表
     * @param planMap       用户id -> 计划列表
     * @param whole         show all user
     */
    private List<User> filterUsersByData(List<User> allUsers, List<LocalDate> dateRange,
                                         Map<Integer, List<WorkReport>> workReportMap,
                                         Map<Integer, List<Plan>> planMap, Boolean whole) {
        // whole=true 显示所有用户
        if (Boolean.TRUE.equals(whole)) {
            return allUsers;
        }
        return allUsers.stream()
                .filter(u -> {
                    List<WorkReport> wrs = workReportMap.get(u.getId());
                    List<Plan> pls = planMap.get(u.getId());
                    boolean hasWork = wrs != null && wrs.stream()
                            .anyMatch(wr -> dateRange.contains(wr.getDate()));
                    boolean hasPlan = pls != null && pls.stream()
                            .anyMatch(pl -> dateRange.contains(pl.getDate()));

                    return hasWork || hasPlan;
                })
                .collect(Collectors.toList());
    }

}
